grammar logo3;



tokens {
    MOVE    	= 'MOVE' ;
    TURN   	= 'TURN' ;
    PENUP    	= 'PENUP' ;
    PENDOWN 	= 'PENDOWN' ;
    IF 		= 'IF';
    WHILE 	= 'WHILE';
    COPEN	= '[';
    CCLOSE	= ']';
    VAR		= 'VAR';
    COMMA	= ';';
    ELSE	= 'ELSE';
    THEN	= 'THEN';
    PROC	= 'PROC';
    CALL	= 'CALL';    
    TRUE	= 'TRUE';   
    FALSE	= 'FALSE';
    PROCREC	= 'PROCREC';
    REPEAT	= 'REPEAT';
    FOR		= 'FOR';
    NIL		= 'NIL';
    PAIR	= 'PAIR?';
    CAR 	= 'CAR';
    CDR		= 'CDR';
    CONS	= 'CONS';
    FUN		= 'FUN';  
    FUNREC	= 'FUNREC';
    TRY		= 'TRY';
    CATCH	= 'CATCH'; 
    THROW 	= 'THROW';
    BREAK	= 'BREAK';
    PT		= 'VAR*';
}

@header {
      package Antlr;
      import AST.*;
      import bool.*;
      import command.*;
      import dec.*;
      import expression.*;      
}

@lexer::header{
      package Antlr;
}




start	returns [Start result]:	
  prog EOF                            { $result = new Start($prog.result); };

prog 	returns [Prog result]:	
  COPEN commands CCLOSE               { $result = new Prog($commands.result); };

commands returns [Commands result]:	{$result = new Commands();}  
	|	command                 {$result = new Commands($command.result);}
	  (COMMA cmds=commands 		{$result.addCommands($cmds.result);})		 ?          
	 ;
	
command returns [Command result]:	
    MOVE expression                   		{$result = new Move($expression.result);}
	|	TURN expression                   {$result = new Turn($expression.result);}
	|	PENUP                             {$result = new Penup();}
	|	PENDOWN                           {$result = new Pendown();}
	| IF expression ifB=prog            	{$result = new If($expression.result,$ifB.result, null);}
	      (ELSE elseB=prog 			{((If)$result).setElseBranch($elseB.result);}
	      )	?            
  | WHILE expression prog             {$result = new While($expression.result, $prog.result); }
  	(Ident {((While)$result).setName($Ident.getText());})?
  | dec                               {$result = $dec.result;}
  | CALL Ident expressions            {$result = new Call($Ident.getText(), $expressions.result);}
  | Ident ':=' expression             {$result = new Affect($Ident.getText(),$expression.result );} 
  | '!' Ident ':=' e1=expression      {$result = new AffectPt($Ident.getText(), $e1.result);}
  | REPEAT expression prog            {$result = new Repeat($expression.result, $prog.result); }
  	(Ident {((Repeat)$result).setName($Ident.getText());})?
  | FOR i1=Ident ';' exp=expression ';' exp2=expression prog   {$result = new For($i1.getText(), $exp.result, $exp2.result, $prog.result); }
  	(i2=Ident {((For)$result).setName($i2.getText());})?
  | THROW 				{$result = new Throw();}
  	(Ident {((Throw)$result).setIdent($Ident.getText());})?				
  | BREAK 				{$result = new Break();}
  	(Ident {((Break)$result).setIdent($Ident.getText());})?				
  | TRY {String s=null;}
  	t=prog 
  	CATCH (Ident{s=$Ident.getText();})? 
  	c=prog		{$result = new Try(s, $t.result, $c.result);}
	
	;

expressions returns [Expressions result]: 	{$result = new Expressions();}
  | e3=expression 				{$result = new Expressions(); $result.addExpression($e3.result);}    		                
      e=expressions				{$result.addExpressions($e.result);}       	
  ;                    

expression returns [IExpression result]:	
	e2=expression_sub			{$result = $e2.result;}
		(Op e3=expression		{$result = new OP($Op.getText(), $e2.result, $e3.result);}
		)?
	
	; 

expression_sub returns [IExpression result]:
	  Num					{$result = new Num($Num.getText());}
	| Ident				{$result = new Ident($Ident.getText());}
		('('e4=expressions')'		{$result = new CallFun($Ident.getText(), $e4.result);}
		)?
	
	| '&' Ident				{$result = new Addr($Ident.getText());}		
	| '!' Ident				{$result = new ValPt($Ident.getText());} 
	| TRUE 					{$result = new True();}
	| FALSE					{$result = new False();}
	| 'NOT' e1=expression			{$result = new NOT($e1.result);}
	| NIL					{$result = new NIL();}
	| CONS e1=expression '::' e2=expression	{$result = new CONS($e1.result, $e2.result);}
	| CAR e1=expression			{$result = new CAR($e1.result);}
	| CDR e1=expression			{$result = new CDR($e1.result);}
	| PAIR e1=expression			{$result = new PAIR($e1.result);}
	| '?('e1=expression')' e2=expression ':' e3=expression    {$result = new Ternaire($e1.result, $e2.result, $e3.result);}
	;
	
idents  returns [Idents result] : 
    Ident                             {$result = new Idents(); $result.addIdent($Ident.getText());}   
  | Ident i=idents                      {$result = new Idents(); $result.addIdent($Ident.getText()); $result.addIdent($i.result);}
  ;
  
dec  returns [Dec result]: 
    PROC Ident idents '=' prog        {$result = new Proc($Ident.getText(), $idents.result, $prog.result, false);}
  | PROCREC Ident idents '=' prog     {$result = new Proc($Ident.getText(), $idents.result, $prog.result, true);}
  | FUN Ident idents '=' expressions  {$result = new Fun($Ident.getText(), $idents.result, $expressions.result, false );}
  | FUNREC Ident idents '=' expressions       {$result = new Fun($Ident.getText(), $idents.result, $expressions.result, true );}
  | VAR Ident 					{$result = new Var($Ident.getText()); }
  	(':=' COPEN expression CCLOSE {((Var)$result).setExpr($expression.result);})? 
  | PT Ident				{$result = new Pointer($Ident.getText());}
  ; 

  
  
Ident  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
	
Num :	'-'? '0'..'9'+
    ;

	
Op	:	'+'
	|	'-'
	|	'*'
	|	'/'
	|	'&&'
	|	'||'
	|	'=='
	|	'<'
	|	'>'
	| 	'>='
	| 	'<='
	;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;